package mq

import (
	"log/slog"

	amqp "github.com/rabbitmq/amqp091-go"
)

type ExchangeDeclareConfig struct {
	Name       string
	Kind       string
	Durable    bool
	AutoDelete bool
	Internal   bool
	NoWait     bool
	Args       amqp.Table
}

type QueueBindConfig struct {
	Name     string
	Key      string
	Exchange string
	NoWait   bool
	Args     amqp.Table
}

// DeclareExchange 安全声明交换机, 创建新 channel (需自行控制 channel 关闭)并尝试声明, 错误转为已定义错误
func (mq *MessageQueue) DeclareExchange(
	config ExchangeDeclareConfig,
) (*amqp.Channel, error) {
	channel, err := mq.Channel()
	if err != nil {
		return nil, err
	}

	if err := mq.DeclareExchangeWithChannel(channel, config); err != nil {
		channel.Close()
		return nil, err
	}

	return channel, nil
}

// DeclareExchangeWithChannel 使用已有 channel 安全声明交换机, 错误转为已定义错误
func (mq *MessageQueue) DeclareExchangeWithChannel(
	channel *amqp.Channel, config ExchangeDeclareConfig,
) error {
	if err := channel.ExchangeDeclare(
		config.Name,
		config.Kind,
		config.Durable,
		config.AutoDelete,
		config.Internal,
		config.NoWait,
		config.Args,
	); err != nil {
		slog.Error(
			"exchange declare error",
			slog.String("exchange", config.Name),
			slog.String("kind", config.Kind),
			slog.String("msg", err.Error()),
		)
		return ErrDeclareExchange
	}

	return nil
}

// QueueBind 绑定队列到交换机, 创建新 channel (需自行控制 channel 关闭)并尝试绑定, 错误转为已定义错误
func (mq *MessageQueue) QueueBind(config QueueBindConfig) (*amqp.Channel, error) {
	channel, err := mq.Channel()
	if err != nil {
		return nil, err
	}

	if err := mq.QueueBindWithChannel(channel, config); err != nil {
		channel.Close()
		return nil, err
	}

	return channel, nil
}

// QueueBindWithChannel 使用已有 channel 绑定队列到交换机, 错误转为已定义错误
func (mq *MessageQueue) QueueBindWithChannel(
	channel *amqp.Channel, config QueueBindConfig,
) error {
	if err := channel.QueueBind(
		config.Name,
		config.Key,
		config.Exchange,
		config.NoWait,
		config.Args,
	); err != nil {
		return ErrQueueBind
	}

	return nil
}
